public class EventBarrier implements Runnable{
	
	private int numWorkers;
	private int numWaiters;
	boolean isSignaled;
	
	public EventBarrier(int workers) {
		numWorkers = workers;
		numWaiters = 0;
		isSignaled = false;
	}
	
	public synchronized void signal() {
		this.notifyAll();
		isSignaled = true;
		System.out.println("Threads Notified");
		while(waiters() != 0) {
			try {
				System.out.println("Controller Waiting");
				this.wait();
			}
			catch (InterruptedException e1) {
				
			}
		}
		isSignaled = false;
		System.out.println("Controller Finished");
		this.notifyAll();
	}
	
	public synchronized void Wait() {
		numWaiters++;
		System.out.println(Thread.currentThread().getName() + " Waiting");
		while (!isSignaled) {
			try {
				this.wait();
			}
			catch (InterruptedException e1) {}
		}
		complete();
		System.out.println(Thread.currentThread().getName() + " Complete");
		if (waiters() == 0)
			this.notify();
		while (isSignaled) {
			try {
				this.wait();
			}
			catch (InterruptedException e1) {}
		}
		System.out.println(Thread.currentThread().getName() + " Finished");	
	}
	
	public synchronized void complete() {
		numWaiters--;
		System.out.println(waiters());
	}
	
	public int waiters() {
		return numWaiters;
	}
	
	public void run() {
		if (Thread.currentThread().getName().equals("Controller"))
			signal();
		else
			Wait();
	}
	
	public static void main(String args[]) {
		EventBarrier barrier = new EventBarrier(3);
		Thread t1 = new Thread(barrier, "Thread 1");
		Thread t2 = new Thread(barrier, "Thread 2");
		Thread controller = new Thread(barrier, "Controller");
		Thread t3 = new Thread(barrier, "Thread 3");
		
		t1.start();
		t2.start();
		controller.start();
		t3.start();
	}
}

